From 2442eccf6d37ed84a45a03b7fa0c1af58b1f0c80 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Mon, 31 Oct 2005 10:45:31 +0100 Subject: [PATCH] Sanitise the trace-buffer hypervisor<->user interface. Signed-off-by: Keir Fraser --- tools/libxc/xenctrl.h | 10 +++---- tools/xentrace/xentrace.c | 58 +++++++++----------------------------- xen/common/trace.c | 35 +++++++++++++---------- xen/include/public/trace.h | 11 +++----- xen/include/xen/trace.h | 1 - 5 files changed, 41 insertions(+), 74 deletions(-) diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index 42ce3097be..767a8ed01c 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -507,12 +507,10 @@ long xc_get_tot_pages(int xc_handle, uint32_t domid); int xc_tbuf_enable(int xc_handle, int enable); /** - * This function sets the size of the trace buffers. Setting it to zero - * deallocates the memory used for trace buffers, and setting it to a - * non-zero value specifies the number of pages per cpu to allocate. - * To change the size of an existing allocation, you must first deallocate - * it then reallocate it. No change in size is allowed when tracing is - * enabled; A disable call must be made first. + * This function sets the size of the trace buffers. Setting the size + * is currently a one-shot operation that may be performed either at boot + * time or via this interface, not both. The buffer size must be set before + * enabling tracing. * * @parm xc_handle a handle to an open hypervisor interface * @parm size the size in pages per cpu for the trace buffers diff --git a/tools/xentrace/xentrace.c b/tools/xentrace/xentrace.c index f927a24f83..18105a19b7 100644 --- a/tools/xentrace/xentrace.c +++ b/tools/xentrace/xentrace.c @@ -23,9 +23,6 @@ #include "xc_private.h" -typedef struct { int counter; } atomic_t; -#define _atomic_read(v) ((v).counter) - #include extern FILE *stderr; @@ -148,7 +145,7 @@ struct t_buf *map_tbufs(unsigned long tbufs_mfn, unsigned int num, } tbufs_mapped = xc_map_foreign_range(xc_handle, 0 /* Dom 0 ID */, - size * num, PROT_READ, + size * num, PROT_READ | PROT_WRITE, tbufs_mfn); xc_interface_close(xc_handle); @@ -240,10 +237,7 @@ struct t_buf **init_bufs_ptrs(void *bufs_mapped, unsigned int num, * mapped in user space. Note that the trace buffer metadata contains machine * pointers - the array returned allows more convenient access to them. */ -struct t_rec **init_rec_ptrs(unsigned long tbufs_mfn, - struct t_buf *tbufs_mapped, - struct t_buf **meta, - unsigned int num) +struct t_rec **init_rec_ptrs(struct t_buf **meta, unsigned int num) { int i; struct t_rec **data; @@ -256,38 +250,11 @@ struct t_rec **init_rec_ptrs(unsigned long tbufs_mfn, } for ( i = 0; i < num; i++ ) - data[i] = (struct t_rec *)(meta[i]->rec_addr - (tbufs_mfn<rec_idx); - - return tails; -} - /** * get_num_cpus - get the number of logical CPUs */ @@ -329,7 +296,6 @@ int monitor_tbufs(FILE *logfile) struct t_buf **meta; /* pointers to the trace buffer metadata */ struct t_rec **data; /* pointers to the trace buffer data areas * where they are mapped into user space. */ - unsigned long *cons; /* store tail indexes for the trace buffers */ unsigned long tbufs_mfn; /* mfn of the tbufs */ unsigned int num; /* number of trace buffers / logical CPUS */ unsigned long size; /* size of a single trace buffer */ @@ -346,19 +312,22 @@ int monitor_tbufs(FILE *logfile) size_in_recs = (size - sizeof(struct t_buf)) / sizeof(struct t_rec); /* build arrays of convenience ptrs */ - meta = init_bufs_ptrs (tbufs_mapped, num, size); - data = init_rec_ptrs (tbufs_mfn, tbufs_mapped, meta, num); - cons = init_tail_idxs (meta, num); + meta = init_bufs_ptrs(tbufs_mapped, num, size); + data = init_rec_ptrs(meta, num); /* now, scan buffers for events */ while ( !interrupted ) { - for ( i = 0; ( i < num ) && !interrupted; i++ ) - while( cons[i] != _atomic_read(meta[i]->rec_idx) ) + for ( i = 0; (i < num) && !interrupted; i++ ) + { + while ( meta[i]->cons != meta[i]->prod ) { - write_rec(i, data[i] + cons[i], logfile); - cons[i] = (cons[i] + 1) % size_in_recs; + rmb(); /* read prod, then read item. */ + write_rec(i, data[i] + meta[i]->cons % size_in_recs, logfile); + mb(); /* read item, then update cons. */ + meta[i]->cons++; } + } nanosleep(&opts.poll_sleep, NULL); } @@ -366,7 +335,6 @@ int monitor_tbufs(FILE *logfile) /* cleanup */ free(meta); free(data); - free(cons); /* don't need to munmap - cleanup is automatic */ fclose(logfile); diff --git a/xen/common/trace.c b/xen/common/trace.c index becdaff853..9746b75102 100644 --- a/xen/common/trace.c +++ b/xen/common/trace.c @@ -37,6 +37,8 @@ integer_param("tbuf_size", opt_tbuf_size); /* Pointers to the meta-data objects for all system trace buffers */ static struct t_buf *t_bufs[NR_CPUS]; +static struct t_rec *t_recs[NR_CPUS]; +static int nr_recs; /* a flag recording whether initialization has been done */ /* or more properly, if the tbuf subsystem is enabled right now */ @@ -70,6 +72,8 @@ static int alloc_trace_bufs(void) nr_pages = num_online_cpus() * opt_tbuf_size; order = get_order_from_pages(nr_pages); + nr_recs = (opt_tbuf_size * PAGE_SIZE - sizeof(struct t_buf)) / + sizeof(struct t_rec); if ( (rawbuf = alloc_xenheap_pages(order)) == NULL ) { @@ -84,13 +88,11 @@ static int alloc_trace_bufs(void) for_each_online_cpu ( i ) { buf = t_bufs[i] = (struct t_buf *)&rawbuf[i*opt_tbuf_size*PAGE_SIZE]; - - _atomic_set(buf->rec_idx, 0); - buf->rec_num = (opt_tbuf_size * PAGE_SIZE - sizeof(struct t_buf)) - / sizeof(struct t_rec); - buf->rec = (struct t_rec *)(buf + 1); - buf->rec_addr = __pa(buf->rec); + buf->cons = buf->prod = 0; + buf->nr_recs = nr_recs; + t_recs[i] = (struct t_rec *)(buf + 1); } + return 0; } @@ -223,9 +225,9 @@ int tb_control(dom0_tbufcontrol_t *tbc) void trace(u32 event, unsigned long d1, unsigned long d2, unsigned long d3, unsigned long d4, unsigned long d5) { - atomic_t old, new, seen; struct t_buf *buf; struct t_rec *rec; + unsigned long flags; BUG_ON(!tb_init_done); @@ -249,17 +251,15 @@ void trace(u32 event, unsigned long d1, unsigned long d2, buf = t_bufs[smp_processor_id()]; - do + local_irq_save(flags); + + if ( (buf->prod - buf->cons) >= nr_recs ) { - old = buf->rec_idx; - _atomic_set(new, (_atomic_read(old) + 1) % buf->rec_num); - seen = atomic_compareandswap(old, new, &buf->rec_idx); + local_irq_restore(flags); + return; } - while ( unlikely(_atomic_read(seen) != _atomic_read(old)) ); - - wmb(); - rec = &buf->rec[_atomic_read(old)]; + rec = &t_recs[smp_processor_id()][buf->prod % nr_recs]; rdtscll(rec->cycles); rec->event = event; rec->data[0] = d1; @@ -267,6 +267,11 @@ void trace(u32 event, unsigned long d1, unsigned long d2, rec->data[2] = d3; rec->data[3] = d4; rec->data[4] = d5; + + wmb(); + buf->prod++; + + local_irq_restore(flags); } /* diff --git a/xen/include/public/trace.h b/xen/include/public/trace.h index 9b3c4d5c0c..47b4bdd189 100644 --- a/xen/include/public/trace.h +++ b/xen/include/public/trace.h @@ -65,13 +65,10 @@ struct t_rec { * field, indexes into an array of struct t_rec's. */ struct t_buf { - /* Used by both Xen and user space. */ - atomic_t rec_idx; /* the next record to save to */ - unsigned int rec_num; /* number of records in this trace buffer */ - /* Used by Xen only. */ - struct t_rec *rec; /* start of records */ - /* Used by user space only. */ - unsigned long rec_addr; /* machine address of the start of records */ + unsigned int cons; /* Next item to be consumed by control tools. */ + unsigned int prod; /* Next item to be produced by Xen. */ + unsigned int nr_recs; /* Number of records in this trace buffer. */ + /* 'nr_recs' records follow immediately after the meta-data header. */ }; #endif /* __XEN_PUBLIC_TRACE_H__ */ diff --git a/xen/include/xen/trace.h b/xen/include/xen/trace.h index e09051c259..a3e6b55654 100644 --- a/xen/include/xen/trace.h +++ b/xen/include/xen/trace.h @@ -24,7 +24,6 @@ #define __XEN_TRACE_H__ #include -#include #include #include -- 2.30.2